<?php

namespace Shared\LRC;

class Manager {

    /**
     * @var \Shared\LRC\Entity\TranslatableI
     */
    private $Object;

    /**
     *
     * @var \Doctrine\ORM\EntityManager
     */
    private $EntityManager;

    /**
     *
     * @var \Shared\LRC\Metadata\EntityMetadata
     */
    private $EntityMetadata;

    /**
     *
     * @var \Shared\LRC\Metadata\TranslationMetadata 
     */
    private $TranslationMetadata;

    /**
     * 
     * @param \Shared\LRC\Entity\TranslatableI $Object
     */
    public function __construct(\Shared\LRC\Entity\TranslatableI $Object) {
        $this->EntityManager = \Shared\Application::instance()->getEntityManager();
        $this->Object = $Object;
        $this->parseMetadata();
    }

    private function parseMetadata() {
        $EntityParser = new \Shared\LRC\Metadata\Parsers\Entity($this->Object, $this->EntityManager);
        $this->EntityMetadata = $EntityParser->parse();

        $TranslationParser = new \Shared\LRC\Metadata\Parsers\Translation($this->EntityMetadata->getTranslationEntityClass(), $this->EntityManager);
        $this->TranslationMetadata = $TranslationParser->parse();
    }

    /**
     * @param \Shared\Entity\Language $Language
     * @param string $property
     * @param string $value
     */
    public function set($Language, $property, $value) {
        $translationProperty = $this->EntityMetadata->getTranslationPropertyName();
        $objectProperty = $this->TranslationMetadata->getObjectPropertyName();
        $languageProperty = $this->TranslationMetadata->getLanguagePropertyName();

        $Collection = $this->Object->{'get' . ucfirst($translationProperty)}();
        foreach ($Collection as $CurrentTranslation) {
            $TranslationLanguage = $CurrentTranslation->{'get' . ucfirst($languageProperty)}();
            if ($TranslationLanguage == $Language) {
                $Translation = $CurrentTranslation;
                break;
            }
        }
        $setMethod = 'set' . ucfirst($property);
        if (!isset($Translation) || !$Translation) {
            $classname = '\\' . $this->EntityMetadata->getTranslationEntityClass();
            $Translation = new $classname;
            $Translation->{'set' . ucfirst($languageProperty)}($Language);
            $Translation->{'set' . ucfirst($objectProperty)}($this->Object);
            $this->EntityManager->persist($Translation);
            $Collection->add($Translation);
        }
        $Translation->{$setMethod}($value);

        if ($this->Object->getId()) {
            $cacheImpl = $this->EntityManager->getConfiguration()->getResultCacheImpl();
            if ($cacheImpl) {
                $cacheImpl->delete(\Shared\LRC\Event\EventSubscriber::getResultCacheId($this->Object, $Language));
            }
        }

        if ($Language == \Shared\Application::instance()->getLRCSupport()->getCurrentLanguage()) {
            $this->Object->{$setMethod}($value);
        }
    }

    /**
     * 
     * @param string $property
     * @param array $values
     */
    public function setValues($property, $values) {
        foreach ($values as $languageId => $value) {
            $Language = $this->EntityManager->getReference('Shared\Entity\Language', $languageId);
            $this->set($Language, $property, $value);
        }
    }

    /**
     * 
     * @param string $property
     * @return array
     * @throws \Shared\LRC\InvalidLRCPropertyException
     */
    public function getLRCValues($property) {
        $lrcValuesArray = array();

        $lrcProperties = $this->getLrcProperties();

        //Check if $property is valid mapped LRC property
        if (!in_array($property, $lrcProperties)) {
            $className = \Doctrine\Common\Util\ClassUtils::getRealClass(get_class($this->Object));
            throw new InvalidLRCPropertyException(sprintf('LRC Exception: `$%s` is not a valid mapped LRC property in %s', $property, $className));
        }
        $translations = $this->Object->{'get' . ucfirst($this->EntityMetadata->getTranslationPropertyName())}();

        foreach ($translations as $Translation) {
            $Language = $Translation->{'get' . ucfirst($this->TranslationMetadata->getLanguagePropertyName())}();
            $lrcValuesArray[$Language->getId()] = $Translation->{'get' . ucfirst($property)}();
        }
        return $lrcValuesArray;
    }

    /**
     * @return array
     */
    public function getLRCContent() {
        $lrcContent = array();
        $translations = $this->Object->{'get' . ucfirst($this->EntityMetadata->getTranslationPropertyName())}();
        $lrcProperties = $this->getLRCProperties();

        foreach ($translations as $Translation) {
            foreach ($lrcProperties as $property) {
                $Language = $Translation->{'get' . ucfirst($this->TranslationMetadata->getLanguagePropertyName())}();
                $lrcContent[$Language->getId()][$property] = $Translation->{'get' . ucfirst($property)}();
            }
        }

        return $lrcContent;
    }

    /**
     * 
     * @return array
     */
    public function getLRCProperties() {
        return array_merge($this->EntityMetadata->getLrcProperties(), $this->EntityMetadata->getLrcAssociations());
    }

    /**
     * 
     * @return string
     */
    public function getLRCPropertiesJSON() {
        return json_encode($this->getLRCProperties());
    }

    /**
     * 
     * @return string
     */
    public function getLRCContentJSON() {
        return json_encode($this->getLRCContent());
    }

    public function get($property, \Shared\Entity\Language $Language = null) {
        if ($Language && $Language != \Shared\Application::instance()->getLRCSupport()->getCurrentLanguage()) {
            $lrcProperties = $this->getLrcProperties();

            //Check if $property is valid mapped LRC property
            if (!in_array($property, $lrcProperties)) {
                $className = \Doctrine\Common\Util\ClassUtils::getRealClass(get_class($this->Object));
                throw new InvalidLRCPropertyException(sprintf('LRC Exception: `$%s` is not a valid mapped LRC property in %s', $property, $className));
            }
            $translations = $this->Object->{'get' . ucfirst($this->EntityMetadata->getTranslationPropertyName())}();

            foreach ($translations as $Translation) {
                $TranslationLanguage = $Translation->{'get' . ucfirst($this->TranslationMetadata->getLanguagePropertyName())}();
                if ($Language == $TranslationLanguage) {
                    return $Translation->{'get' . ucfirst($property)}();
                }
            }
        } else {
            return $this->Object->{'get' . ucfirst($property)}();
        }
    }

}
